//
// Created by abstergo on 24-6-19.
//

#ifndef TBS_CPP_LINKLISTINL_CUH
#define TBS_CPP_LINKLISTINL_CUH

template<typename T> NodeIterator<T> LinkList<T>::begin() noexcept {
  return NodeIterator<T>(_head.after());
}

template<typename T> NodeIterator<T> LinkList<T>::end() noexcept {
  return NodeIterator<T>(nullptr);
}

template<typename T> NodeIterator<T> LinkList<T>::begin() CONST noexcept {
  return NodeIterator<T>(const_cast<node *>(_head.after()));
}

template<typename T> NodeIterator<T> LinkList<T>::end() CONST noexcept {
  return NodeIterator<T>(nullptr);
}

template<typename T> LinkList<T>::LinkList(const LinkList &other) {
  *this = other;
}

template<typename T> LinkList<T>::LinkList(LinkList &&other) NO_EXCEPT {
  *this = std::forward<LinkList>(other);
}

template<typename T> LinkList<T> &LinkList<T>::operator=(const LinkList &other) {
  for (auto i : other) {
	this->append_with_copy(i.value());
  }
  return *this;
}

template<typename T> LinkList<T> &LinkList<T>::operator=(LinkList &&other) NO_EXCEPT {
  this->_head = std::move(other._head);
  this->_tail = std::move(other._tail);
  other._head.after() = nullptr;
  other._tail = &other._head;
  return *this;
}

template<typename T> void LinkList<T>::insert(const size_t &index, T &&val) {
  operateNode([&](node &i, node &t, node &h, const size_t &idx, bool &stop) {
	if (idx == index) {
	  node *v = new node();
	  v->value() = std::forward<T>(val);
	  if (i.has_pre()) {
		v->pre() = i.pre();
		i.pre()->after() = v;
	  }
	  v->after() = &i;

	  return true;
	}
	return false;
  });
}

template<typename T> void LinkList<T>::insert(const size_t &index, const T &val) {
  insert(index, val);
}

template<typename T> void LinkList<T>::merge(LinkList &&other) {
  operateNode([&](node &now, node &tail, node &head, const size_t &index, bool &stop) {
	stop = true;
	if (other._head.has_after()) {
	  LinkNode<T> *pre, *af;
	  disconnect(*other._head.after(), pre, af);
	  other._tail = &_head;
	  connectAfter(tail, *(af));
	  while (af != nullptr) {
		if (af->has_after()) {
		  af = af->after();
		} else {
		  tail = *af;
		  break;
		}
	  }
	}
  });
}

template<typename T> void LinkList<T>::clear() {
  if (_head.has_after()) {
	node *t = _head.after();
	while (t->has_after()) {
	  node *n = t->after();
	  delete t;
	  t = n;
	}
	if (_tail != &_head) {
	  delete _tail;
	  _tail = &_head;
	}
  }
}

template<typename T> void LinkList<T>::operateNode(node_operate_function _f, bool is_reverse) {
  auto be = is_reverse ? end() : begin();
  auto en = is_reverse ? begin() : end();
  auto &idx = is_reverse ? en : be;
  size_t i = 0;
  bool stop_flag = false;
  while (idx != en && !stop_flag) {
	_f(idx.value(), *_tail, _head, i++, stop_flag);
	auto op = &idx;
	if (is_reverse) {
	  op = &en;
	}
	if (!op->has_next()) {
	  break;
	}
	op->next();
  }
}

template<typename T> void LinkList<T>::append(T &&value) {
  node *node1 = new node();
  node1->value() = std::forward<T>(value);
  _tail->after() = node1;
  node1->pre() = _tail;
  _tail = node1;
}

template<typename T> void LinkList<T>::append_with_copy(const T &value) {
  this->append(T(value));
}

template<typename T> LinkList<T>::~LinkList() {
  clear();
}

template<typename T> LinkList<T>::LinkList() {
}

#endif //TBS_CPP_LINKLISTINL_CUH
